<template>
  <div class="swiper--wrapper">
    <ul class="swiper-nav" :class="'swiper-nav--' + direction">
      <li class="swiper-nav--item" :class="{'swiper-nav--item-active': item === navs[activeIndex]}" v-for="(item,index) in navs" :key="index">
        <a href="javascript:void(0);">{{item}}</a></li>
      <div class="swiper-nav--active-line"></div>
    </ul>
    <div class="swiper" :class="direction" @touchstart="_onTouchStart" @touchmove="_onTouchMove" @touchend="_onTouchEnd">
      <div :style="{
                'transform' : 'translate3d(' + translateX + 'px,' + translateY + 'px, 0)',
                'transition-duration': transitionDuration + 'ms'
             }"><slot></slot></div>
    </div>
  </div>
</template>
<script>
  const VERTICAL = 'vertical'
  const HORIZONTAL = 'horizontal'

  export default {
    name: 'Swiper',
    props: {
      initialIndex: {
        type: Number,
        default: 0
      },
      autoplay: {
        type: Boolean,
        default: false
      },
      interval: {
        type: Number,
        default: 3000
      },
      speed: {
        type: Number,
        default: 500
      },
      nested: {
        type: Boolean,
        default: false
      },
      direction: {
        type: String,
        default: HORIZONTAL,
        validator: (value) => [VERTICAL, HORIZONTAL].indexOf(value) > -1
      },
    },
    data () {
      return {
        items: [],
        swiperWidth: 0,
        activeIndex: 0,
        lastIndex: 0,
        containerWidth: 0,
        timer: null,
        translateX: 0,
        translateY: 0,
        lastPage: 0,
        translateStartTime: null,
        translateStartPosition: 0,
        transitionDuration: 0,
        transitioning: false, //是否在transition状态
        navs: [] // nav导航
      }
    },
    computed: {
      hasLabel () {
        return this.items.some(item => item.label.toString().length > 0)
      }
    },
    methods: {
      playSlides () {
        if (this.activeIndex < this.items.length - 1) {
          this.activeIndex++
        } else {
          this.activeIndex = 0
        }
      },
      startTimer () {
        if (this.interval <= 0 || !this.autoplay) return
        this.timer = setInterval(this.playSlides, this.interval)
      },
      pauseTimer () {
        clearInterval(this.timer)
      },
      setActiveItem (index, noAnimation) {
        // index 可以为name
        if (typeof index === 'string') {
          const filterItems = this.items.filter(item => item.name === index)
          if (filterItems.length > 0) {
            index = this.items.indexOf(filterItems[0])
          }
        }
        index = Number(index)
        if (isNaN(index) || index !== Math.floor(index)) {
          process.env.NODE_ENV !== 'production' &&
          console.warn('[Element Warn][Carousel]index must be an integer.')
          return
        }
        let length = this.items.length
        this.lastPage = this.activeIndex
        if(index < 0){
          this.activeIndex = this.items.length
        }else if(index >= this.items.length){
          this.activeIndex = 0
        }else {
          this.activeIndex = index
        }
        if(this.loop){
          //todo loop 处理
          if(this.delta === 0){
            this._setTranslate(this._getTranslateOfPage(this.lastPage))
          }

        }else {
          this._setTranslate(this._getTranslateOfPage(index))
          if (noAnimation) return
          this._onTransitionStart()
        }
      },
      prev () {
        this.setActiveItem(this.activeIndex - 1)
      },
      next () {
        this.setActiveItem(this.activeIndex + 1)
      },
      _revert () {
        this.setActiveItem(this.activeIndex)
      },
      updateItems () {
        this.items = this.$children.filter(child => child.$options.name === 'SwiperItem')
        // 更新 navs
        const navs = []
        this.items.forEach(item => {
          navs.push(item.label)
        })
        this.navs = navs
      },
      _onTouchStart (e) {
        this.pauseTimer()
        this.startPos = this._getTouchPos(e)
        this.delta = null // 滑动位移
        // this.startTranslate
        this.dragging = true
        this.firstMove = true
        this.slidingDirection = null
        this.transitionDuration = 0
        this.translateStartPosition = this._getTranslateOfPage(this.activeIndex)
        this.translateStartTime = new Date().getTime()
      },
      _onTouchMove (e) {
        if(!this.dragging){
          return
        }
        let deltaX = this._getTouchPos(e).x - this.startPos.x
        let deltaY = this._getTouchPos(e).y - this.startPos.y
        if (!deltaX && !deltaY) return
        if (this.firstMove) {
          // 第一次滑动用来判断用户滑动的方向
          this.firstMove = false
          if (Math.abs(deltaY) >= Math.abs(deltaX)) {
            this.slidingDirection = VERTICAL
          } else {
            this.slidingDirection = HORIZONTAL
          }
          // 如果滑动方向与swiper方向不一致，解绑此次滑动事件
          if (this.direction !== this.slidingDirection) {
            this.dragging = false
            console.log('滑动方向不一致')
            return
          }
        }
        this.delta = this.direction === HORIZONTAL ? deltaX : deltaY
        this._setTranslate(this.translateStartPosition + this.delta)
      },
      _onTouchEnd () {
        this.dragging = false
        this.transitionDuration = this.speed
        // 判断是否为快速滑动
        const isQuickAction = new Date().getTime() - this.translateStartTime < 600
        if (this.delta < -100 || (isQuickAction && this.delta < -30)){
          this.next()
        } else if (this.delta > 100 || (isQuickAction && this.delta > 30)) {
          this.prev()
        } else {
          this._revert()
        }
      },
      // 获取触摸坐标
      _getTouchPos (e) {
        const x = e.changedTouches ? e.changedTouches[0].pageX : e.pageX
        const y = e.changedTouches ? e.changedTouches[0].pageY : e.pageY
        return {
          x: x,
          y: y
        }
      },
      _setTranslate (value) {
        const translateName = this.direction === HORIZONTAL ? 'translateX' : 'translateY'
        this[translateName] = value
      },
      _onTransitionStart () {
        this.transitioning = true
        this.transitionDuration = this.speed
        if (this._isPageChanged()) {
          this.$emit('slide-change-start', this.currentPage)
        } else {
          this.$emit('slide-revert-start', this.currentPage)
        }
      },
      _onTransitionEnd () {
        this.transitioning = false
        this.transitionDuration = 0
        this.delta = 0
        if (this._isPageChanged()) {
          this.$emit('slide-change-end', this.activeIndex)
        } else {
          this.$emit('slide-revert-end', this.activeIndex)
        }
      },
      _isPageChanged () {
        return this.lastIndex !== this.activeIndex
      },
      // 当前swiper已经translate的距离
      _getTranslateOfPage (page) {
        return -this.swiperWidth * page
      },
    },
    mounted () {
      this.updateItems()
      this.$nextTick(() => {
        if (this.initialIndex < this.items.length && this.initialIndex >= 0) {
          this.activeIndex = this.initialIndex
        }
        this.startTimer()
      })
      this.swiperWidth = parseInt(getComputedStyle(this.$el).width)
    },
    watch: {
      items (val) {
        if (val.length > 0) this.setActiveItem(this.initialIndex)
      },
      autoplay (val) {
        val ? this.startTimer() : this.pauseTimer()
      },
      activeIndex (val, oldVal) {
        this.$emit('change', val, oldVal)
      }
    },
    beforeDestroy () {
      this.pauseTimer()
    }
  }
</script>
<style lang="less">
  @import "../assets/vue2-swiper.less";
</style>
